/** miniplayer主程序文件
 * @file accinfo.cpp
 * @author Kiven Lee
 * @version 1.0
 * @date 2021-08-26
 *
 * @copyright Kivensoft (c) 2018 - 2021
 *
 */

#include <winsock2.h>
#include <windows.h>
#include <Shlwapi.h>
#include <commctrl.h>

#include "klib/log.hpp"
#include "kwin/strconv.hpp"
#include "kwin/path.hpp"

#include "config.hpp"
#include "wkewnd.hpp"
#include "vlcwnd.hpp"

using namespace miniplayer;

// static HHOOK g_hhook = NULL;

// vlc_player消息处理函数
static void OnVlcPlayer(WPARAM wParam, LPARAM lParam) {
    switch (wParam) {
        case (WPARAM) PlayState::play:
            Config::vlc_player.play((char*) lParam);
            delete[] (char *) (lParam);
            break;
        case (WPARAM) PlayState::play_url:
            Config::vlc_player.play_url((char*) lParam);
            delete[] (char *) (lParam);
            break;
        case (WPARAM) PlayState::pause:
            Config::vlc_player.pause();
            break;
        default:
            Config::vlc_player.stop();
            ::PostMessageA(WkeWnd::getWkeHWND(), WM_SETFOCUS, 0, 0);
    }
}

static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        // vlc播放消息，通过消息触发，是为了将vlc的控制全部放到一个线程中进行，避免stop死锁问题
        case WM_VLC_PLAYER:
            return OnVlcPlayer(wParam, lParam), 0;

        case WM_SIZE:
            if (Config::wke_web_view) {
                kwin::Rect rc;
                rc.getClient(hwnd);
                wkeMoveWindow(Config::wke_web_view, 0, 0, rc.width(), rc.height());
            }
            break;

        // 主窗口销毁时发送退出应用的消息，结束应用程序
        case WM_DESTROY:
            PostQuitMessage(0);
            Config::main_hwnd = nullptr;
            break;

        case WM_CREATE:
            Config::main_hwnd = hwnd;
            // 设置窗口关联的用户自定义数据, 数据由创建窗口函数传参得到
            return kwin::SetWindowUserData(hwnd, kwin::GetCreateParamFromLParam(lParam)), 0;

        default:
            return ::DefWindowProcA(hwnd, message, wParam, lParam);
    }

    return 0;
}

[[maybe_unused]]
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    // KBDLLHOOKSTRUCT *data = (KBDLLHOOKSTRUCT*) lParam;
    // LOG_DEBUGF("code = %d, vkCode = %d", nCode, data->vkCode);
    // return ::CallNextHookEx(g_hhook, nCode, wParam, lParam);
    return 0;
}

/** 创建及显示主窗体 */
static bool CreateMainWindow(HINSTANCE hInstance) {
    WNDCLASSEX wcex = {
        .cbSize        = sizeof(WNDCLASSEX),
        .style         = CS_HREDRAW | CS_VREDRAW,
        .lpfnWndProc   = WndProc,
        .cbClsExtra    = 0,
        .cbWndExtra    = 0,
        .hInstance     = hInstance,
        .hIcon         = LoadIcon(NULL, IDI_APPLICATION),
        .hCursor       = LoadCursor(NULL, IDC_ARROW), // (HBRUSH)GetStockObject(LTGRAY_BRUSH),
        .hbrBackground = (HBRUSH)(COLOR_WINDOW + 1),
        .lpszMenuName  = NULL, // MAKEINTRESOURCE(IDC_WKEBROWSER),
        .lpszClassName = Config::app,
        .hIconSm       = LoadIcon(NULL, IDI_APPLICATION)
    };

    if (!::RegisterClassExA(&wcex)) {
        Config::msgbox<MB_ICONERROR>("应用程序运行失败：无法注册窗口类%s!", Config::app);
        return false;
    }

    HWND hwnd = ::CreateWindowExA(0, Config::app, // window class name
            NULL, // window caption
            WS_POPUP, // WS_OVERLAPPEDWINDOW, // window style
            CW_USEDEFAULT, // initial x position
            CW_USEDEFAULT, // initial y position
            CW_USEDEFAULT, // initial x size
            CW_USEDEFAULT, // initial y size
            NULL, // parent window handle
            NULL, // window menu handle
            hInstance, // program instance handle
            NULL); //(LPVOID) &Config::vlc_player); // creation parameters
    if (!hwnd) {
        Config::msgbox<MB_ICONERROR>("创建主窗口失败%s!", Config::app);
        return false;
    }

    // 窗口置顶
    // ::SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE);

    // 最大化显示窗口
    ::ShowWindow(hwnd, SW_SHOWMAXIMIZED);
    ::UpdateWindow(hwnd);

    return true;
}

// 创建浏览器控件
static bool InitWebkit() {
    // 获取node.dll所在位置
    klib::dstring_t<256> dll_path;
    if (kwin::absPathFromApp(dll_path, Config::get_node_dll()) == 0) {
        Config::messagebox("获取应用程序路径错误", MB_ICONERROR);
        return false;
    }
    if (!::PathFileExistsA(dll_path.data())) {
        Config::msgbox<MB_ICONERROR>("请把%s放exe目录下", Config::get_node_dll().data());
        return false;
    }

    // 用node.dll所在路径来初始化浏览器控件
    kwin::wide_chars_t w_dll_path(dll_path.data());
    wkeSetWkeDllPath(w_dll_path.c_str());
    wkeInitialize();

    return WkeWnd::createWebWindow();
}

// 命令行参数解析
static bool ParseCmdLine() {
    klib::dstring_t<256> buf;
    int nArgs = kwin::CmdLineToArgv(buf);

    // 处理命令行参数
    if (nArgs && Config::parse(nArgs, (char**) buf.data()) == false) {
        Config::messagebox("命令行解析失败!", MB_ICONERROR);
        return false;
    }

    return true;
}

// 初始化xp样式的控件风格
void InitCommCtrl() {
    INITCOMMONCONTROLSEX icc = {
        .dwSize = sizeof(INITCOMMONCONTROLSEX),
        .dwICC = ICC_WIN95_CLASSES
    };
    InitCommonControlsEx(&icc);
}

// 应用程序入口
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PSTR szCmdLine, int iCmdShow) {
    Config::hinstance = hInst;

    // 初始化支持xp样式控件
    InitCommCtrl();

    // 解析命令行参数
    if (ParseCmdLine() == false) return 0;

    // 调试模式下，创建控制台用于输出
    if (Config::get_debug()) kwin::open_console();

    // 创建主窗体
    if(CreateMainWindow(hInst) == false) return 0;

    // 创建钩子函数
    // ::SetWindowsHookExA(WH_KEYBOARD_LL, LowLevelKeyboardProc, Config::hinstance, 0);

    // 初始化浏览器控件
    if (InitWebkit() == false) return 0;

    // 消息循环
    HWND wke_hwnd = WkeWnd::getWkeHWND();
    MSG msg;
    while (::GetMessageA(&msg, NULL, 0, 0)) {
        if (msg.message == WM_KEYDOWN) {
            if (msg.hwnd == wke_hwnd) {
                bool c = false;
                switch (msg.wParam) {
                    case VK_ESCAPE:
                        WkeWnd::goHome();
                        break;
                    case VK_RIGHT:
                        ::PostMessageA(wke_hwnd, WM_KEYDOWN, VK_TAB, 0);
                        break;
                    case VK_LEFT:
                        keybd_event(VK_SHIFT, 0, 0, 0);   // Shift + Tab
                        keybd_event(VK_TAB, 0, 0, 0);
                        keybd_event(VK_TAB, 0, KEYEVENTF_KEYUP, 0);
                        keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
                        break;
                    default:
                        c = true;
                }
                if (!c) continue;
            }
        } else if (msg.message == WM_SYSKEYDOWN) {
            if (msg.wParam == 121) {
                ::PostMessageA(Config::main_hwnd, WM_CLOSE, 0, 0);
                continue;
            }
        }
        ::TranslateMessage(&msg);
        ::DispatchMessageA(&msg);
    }

    // ::UnhookWindowsHookEx(g_hhook);

    // 释放浏览器控件占用的资源
    wkeFinalize();

    return msg.wParam;
}

